The problem for ifmon
~~~~~~~~~~~~~~~~~~~~~
The system may need to configure networking interfaces somehow, but networking
interfaces aren't static in Linux. Doing something like this:

	ipcfg eth0 192.168.0.1/24
	ipcfg eth1 192.168.1.1/24
	wifi device wlan0

somewhere in the startup script is not possible. The names of the interfaces
(eth0, eth1, wlan0) are not fixed, and may change on the next boot. It may
take a while until the interfaces actually appear; suspending boot and waiting
for them is not a good idea. Especially for wifi, those take seconds sometimes.

The user should also have some way of reconfiguring the interfaces at runtime.
Preferably without full root rights, which means some kind of "networking
profiles" and a tool to switch between them. Several use cases here:

	* switch eth0 between auto configuration (dhcp) and a bunch of
	  pre-configured static profiles for different networks

	* pin one of several available wifi interfaces to use as
	  the default one for the WPA supplicant

The solution ifmon implements looks like this: let's put configuration
for each interface in a separate script, and have a service that would
call these scripts with the right interface name once the interface
becomes usable.

	/etc/net/mode-uplink:

		#!/sbin/msh

		ipcfg $1 up # to be dhcp'd later

	/etc/net/mode-local:

		#!/sbin/msh

		ip4addr $1 192.168.1.1/24

	/etc/net/mode-wifi:

		#!/sbin/msh

		wifi device $1

The name of the script is the "profile" for the device. The service (ifmon,
short for "interface monitor") now needs to call them with the right interface
names, matching the volatile kernel names to some persistent device properties:

	/etc/net/mode-uplink eth0    # or maybe eth0
	/etc/net/mode-local eth1     # or maybe eth1
	/etc/net/mode-wifi wlan0

This way we can also let the user switch profiles for available interfaces
at runtime. Having configuration scripts also makes this approach reasonably
generic — as long as it can be expressed in a script, it should work.


Interface identification
~~~~~~~~~~~~~~~~~~~~~~~~
When a new interface appears, ifmon spawns

	/etc/net/identify eth0	# or whatever its kernel name is

This script is expected to figure out whether the interfaces needs a profile,
and if so, do an IPC call back to ifmon to set that profile.

The obvious approach would be to let ifmon itself figure out which incoming
kernel devices should be matched to which profiles, basically embedding the
identification code into ifmon. This is not a good idea. Identification code
is tricky, and doesn't really belong within a long-running process. Moving
the code into an external tool means long-running ifmon itself remains very
lean, and most of the unpleasant code (identification, profile matching,
persistent configuration parsing and so on) remain in a short-living tool.


Persistent device names
~~~~~~~~~~~~~~~~~~~~~~~
The approach used in FDO/systemd/udevd is to force some global naming scheme
upon users that would somehow guarantee that the same device always gets the
same name, and just keep using those names as if networking interfaces were
static in Linux. This means, among other bad things, that the user has to deal
with ugly device-id names even if particular host configuration would allow
for something better.

In contrast, ifmon operates with user-defined *profile* names, and only relies
on ifctl's ability to match profiles to some persistent device ids, which
remain internal to ifctl and never get exposed to the user (unless explicitly
asked for).

It is possible to assign persistent user-defined device names to identifiable
devices with ifmon. See below on how it's implemented. Unlike in FDO systems
however, the choice of the naming scheme is free and host-local. If there's
only one LAN and one Wi-Fi card on the host, they can be just "lan" and "wan"
with ifmon, not "enp37s0" and "wlp36s0".

Custom interface names are completely optional for ifmon. It is perfectly
fine to keep the kernel names and just use $1 in relevant profile scripts.


Re-naming devices
~~~~~~~~~~~~~~~~~
Neither ifmon nor Netlink it listens to use device names. Devices are always
referred to using ifindex internally. Interface names passed to the scripts
are obtained from respective ifindexes immediately before spawning the script
via ioctl SIOCGIFNAME.

It is generally fine to re-name devices in mode-* scripts. It's up to the
tool used there to handle name clashes and such. Re-naming back may be done
in stop-* scripts if necessary.


Long-running network-dependent services
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One of the functions ifmon performs is serializing network-related events.
At any given time, at most one `foo $interface` script may be running for
a given $interface. And at most one without an $interface argument. This
is a minor limitation that helps in keeping the scripts simple and sequential,
as if written to run on static devices during system startup.

This design however requires the scripts themselves to be short-running.
If something long-running needs to be started in response to any of
the networking events, the script should send an IPC request somewhere
to start it and exit immediately, instead of trying to start it right
under ifmon.

Another reason to go with indirect exec here is to avoid having process
supervision code within ifmon, beyond the bare minimum required to run event
scripts. Unlike `svhub`, ifmon does not capture the output of the scripts
it runs.

The only exception to this is DHCP, which is expected to run as a direct
child process to ifmon. This is mostly due to the tight coupling between
the two; while current design makes them separate executables, it is possible
to integrate DHCP client functionality into ifmon, it was done like that at
some point, and for instance systemd-networkd does it like that as well.


Stopping and switching interfaces
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
While the mode-* scripts alone are enough to initialize devices once,
switching profiles requires complementary set of stop-* scripts to undo
the changes done in mode-* script, at least in some cases.

Example: mode-wifi might run

	wifi device "$1"

but running `wifi device` twice may not be possible without `wifi detach`
in-between. That's the case with current `wifi` implementation, and it may
be with other tools as well. So for this profile, stop-wifi would be

	wifi detach

Stop scripts are important for long-running link-handling services like wsupp,
but may also come handy when mode-* scripts change the state of the link.
For instance, mode-lan that assigns a static ip and some routes may benefit
from having stop-lan that would flush the interface and the routes.


General Internet connectivity scripts
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Some things may need to happen when the system gains (and loses) internet
connectivity, loosely defined as access to an arbitrary named host. A quick
example would be starting NTP synchronization with subdomain.pool.ntp.org,
or configuring host name resolver in some DHCP-independent manner and so on.

At some point, the idea was the ifmon would track default routes and run
certain scripts when gain (or loss) of internet connectivity is detected.
It turned out to be much more difficult than expected, so the idea got
scrapped.

For static routes, relevant commands should be included near the end of the
profile script. For dynamic (dhcp) routes, `dhcp` itself would run a script
when it gets default-route entry in its packet. Instead of tracking the state
of the kernel routing table, relevant commands are placed right next to where
the route gets added.
